package com.zfl.service.impl;

import com.zfl.entity.User;
import com.zfl.mapper.RoleMapper; // 新增：角色Mapper
import com.zfl.mapper.UserMapper;
import com.zfl.service.LoginService;
import com.zfl.utils.JwtUtils;
import com.zfl.vo.LoginRequestVO;
import com.zfl.vo.LoginResponseVO;
import com.zfl.vo.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
@RequiredArgsConstructor // 自动注入构造函数
@Slf4j
public class LoginServiceImpl implements LoginService {

    // 依赖注入（Redis、JWT工具、用户Mapper、角色Mapper、密码加密器）
    private final RedisTemplate<String, Object> redisTemplate;
    private final JwtUtils jwtUtils;
    private final UserMapper userMapper;
    private final RoleMapper roleMapper; // 用于查询角色名称
    private final BCryptPasswordEncoder passwordEncoder; // 密码比对工具


    @Override
    public Result<LoginResponseVO> login(LoginRequestVO request) {
        String username = request.getUsername();
        String password = request.getPassword();

        // 1. 校验用户名是否存在
        User user = userMapper.selectByUsername(username);
        if (user == null) {
            log.warn("登录失败：用户[{}]不存在", username);
            return Result.fail("用户名或密码错误");
        }

        // 2. 校验用户状态（是否被封禁）
        if (user.getStatus() != 1) { // 假设 1=正常，0=封禁
            long banTime = user.getBanRemainingTime(); // 剩余封禁时间（毫秒）
            log.warn("用户[{}]处于封禁状态，剩余{}毫秒", username, banTime);
            return Result.fail("账号已被封禁，剩余时间：" + (banTime / 1000) + "秒");
        }

        // 3. 校验密码是否正确（BCrypt加密比对）
        if (!passwordEncoder.matches(password, user.getPassword())) {
            log.warn("用户[{}]登录失败：密码错误", username);
            // 这里可添加"密码错误次数累计"逻辑（如超过5次封禁账号）
            return Result.fail("用户名或密码错误");
        }

        // 4. 获取用户角色信息（从role表查询真实角色名）
        Long roleId = userMapper.selectRoleIdByUserId(user.getId()); // 从user_role表查角色ID
        String roleName = roleMapper.selectRoleNameById(roleId); // 从role表查角色名（如"ROLE_USER"）
        log.info("用户[{}]角色信息：roleId={}, roleName={}", username, roleId, roleName);

        // 5. 生成JWT Token（只存userId，不存角色，确保Token轻量）
        String token = jwtUtils.generateToken(user.getId()); // JWT过期时间建议与Redis一致（如2小时）
        // 关键新增：打印Token（建议只在开发/调试环境使用，生产环境需删除，避免安全风险）
        log.info("用户[{}]登录成功，生成JWT Token：{}", username, token);

        // 6. 登录成功后，存储角色信息到 Redis（Hash 结构）
        String redisKey = "user:role:" + user.getId();
        // 登录时存储用户角色到 Redis 前，先检查 Key 类型
        if (redisTemplate.hasKey(redisKey)) {
                redisTemplate.delete(redisKey);
                log.info("已清理旧结构的用户角色数据，Key={}", redisKey);

        }
        // 再用新的 Hash 结构存储角色信息
        redisTemplate.opsForHash().put(redisKey, "roleId", roleId);
        redisTemplate.opsForHash().put(redisKey, "roleName", roleName);   // 角色名称（String类型）
        // 设置过期时间（与JWT一致，2小时）
        redisTemplate.expire(redisKey, 7200, TimeUnit.SECONDS);
        log.info("用户[{}]角色信息已存入Redis Hash，key={}", username, redisKey);

        // 7. 登录成功：重置密码错误次数（如果有）
        user.setPasswordTryCount(0);
        userMapper.updateById(user);

        // 8. 返回登录结果（包含token、userId、角色信息给前端）
        LoginResponseVO response = new LoginResponseVO();
        response.setToken(token);
        response.setUserId(user.getId());
        response.setUsername(username);
        response.setRoleId(roleId);
        response.setRoleName(roleName);

        return Result.success(response);
    }
}